package com.tcxhb.job.core.schedule.execute;

import com.tcxhb.job.common.constants.BaseException;
import com.tcxhb.job.common.model.MiscResult;
import com.tcxhb.job.core.constants.enums.LogActionEnum;
import com.tcxhb.job.core.entity.JobRunDTO;
import com.tcxhb.job.core.schedule.workflow.*;
import com.tcxhb.job.core.schedule.workflow.retry.InstanceRunRetryFlow;
import com.tcxhb.job.core.schedule.workflow.retry.JobRetryCheckFlow;
import com.tcxhb.job.core.utils.LogUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @Description:
 * @Auther: tcxhb
 * @Date: 2023/11/5
 */
@Component
@Slf4j
public class JobRunExecutorImpl implements JobRunExecutor {
    private ExecutorService executor = new ThreadPoolExecutor(
            20, 50, 1000, TimeUnit.SECONDS,
            new LinkedBlockingDeque<>());

    @Autowired
    private JobCheckFlow jobCheckFlow;
    @Autowired
    private ShardingRouteFlow shardingRouteFlow;
    @Autowired
    private InstanceCreateFlow instanceCreateFlow;
    @Autowired
    private InstanceRunFlow instanceRunFlow;
    @Autowired
    private InstanceRunRetryFlow instanceRunRetryFlow;
    @Autowired
    private JobRetryCheckFlow jobRetryCheckFlow;
    @Autowired
    private InstanceBulidFlow instanceBulidFlow;

    @Override
    public MiscResult run(JobRunDTO runDTO) {
        try {
            LogUtils.info(runDTO.getJobId(), runDTO.getScheduleTime(), LogActionEnum.SubmitPool, "");
            JobRunContext context = new JobRunContext(runDTO);
            executor.submit(new Runner(context));
        } catch (Exception e) {
            log.error("submit-pool-exp:" + runDTO.getJobId() + runDTO.getScheduleTime(), e);
            LogUtils.info(runDTO.getJobId(), runDTO.getScheduleTime(), LogActionEnum.SubmitPool, "fail");
        }
        return MiscResult.suc();
    }

    /**
     * 线程任务
     */
    public class Runner extends Thread {
        private JobRunContext context;

        public Runner(JobRunContext context) {
            this.context = context;
        }

        @Override
        public void run() {
            try {
                LogUtils.info(context.getReq().getJobId(), context.getReq().getScheduleTime(), LogActionEnum.ThreadRun, "");
                jobCheckFlow.handle(context);
                shardingRouteFlow.handle(context);
                instanceBulidFlow.handle(context);
                instanceCreateFlow.handle(context);
                instanceRunFlow.handle(context);
            } catch (BaseException e) {
                log.error("job-submit-exp,{},{}", context.getReq().getJobId(), e.getMsg());
                LogUtils.info(context.getReq().getJobId(), context.getReq().getScheduleTime(), LogActionEnum.ThreadRun, e.getMsg());
            } catch (Exception e) {
                log.error("job-submit-exp", e);
                LogUtils.info(context.getReq().getJobId(), context.getReq().getScheduleTime(), LogActionEnum.ThreadRun, "exp");
            }
        }
    }

    @Override
    public MiscResult retry(Long instanceId, boolean runOnce) {
        try {
            JobRunDTO runDTO = new JobRunDTO(null, System.currentTimeMillis());
            runDTO.setInstanceId(instanceId);
            runDTO.setRunOnce(runOnce);
            JobRunContext context = new JobRunContext(runDTO);
            executor.submit(new RetryRunner(context));
        } catch (Exception e) {
            log.error("retry-exp", e);
        }
        return MiscResult.suc();
    }

    /**
     * 重试任务
     */
    public class RetryRunner extends Thread {
        private JobRunContext context;

        public RetryRunner(JobRunContext context) {
            this.context = context;
        }

        @Override
        public void run() {
            try {
                jobRetryCheckFlow.handle(context);
                instanceRunRetryFlow.handle(context);
            } catch (BaseException e) {
                log.error("job-submit-exp:" + e.getMsg());
            } catch (Exception e) {
                log.error("job-submit-exp", e);
            }
        }
    }
}
